package service

import (
	"github.com/gogf/gf/container/gvar"
	"github.com/gogf/gf/database/gdb"
	"github.com/gogf/gf/util/gconv"
	"web_api_gogf/app/dao"
	"web_api_gogf/app/model"
)

// SysRole 系统角色逻辑类
var SysRole = SysRoleService{}

type SysRoleService struct {
}

//获取指定用户的角色ID数组集
func (s *SysRoleService) getUserRoleIds(userId uint) ([]*gvar.Var, error) {
	var userRoleIds []*gvar.Var
	//用户-角色中间表记录数据
	userRoleIds, err := dao.SysRoleUsers.Array("role_id", "user_id", userId)
	if err != nil {
		return nil, err
	}
	return userRoleIds, nil
}

// GetRoleListByUserId 通过用户ID获取角色列表
func (s *SysRoleService) GetRoleListByUserId(userId uint) ([]model.SysRoles, error) {
	//用户-角色中间表记录数据
	userRoleIds, err := s.getUserRoleIds(userId)
	if err != nil {
		return nil, err
	}
	roleList := ([]model.SysRoles)(nil)
	//角色列表
	if err := dao.SysRoles.WhereIn("role_id", userRoleIds).Scan(&roleList); err != nil {
		return nil, err
	}
	return roleList, nil
}

// GetRoleNameListByUserId 获取角色名称列表
func (s *SysRoleService) GetRoleNameListByUserId(userId uint) ([]*gvar.Var, error) {
	//用户-角色中间表记录数据
	userRoleIds, err := s.getUserRoleIds(userId)
	if err != nil {
		return nil, err
	}
	var roleNameList []*gvar.Var
	roleNameList, err = dao.SysRoles.WhereIn("role_id", userRoleIds).Array("name")
	if err != nil {
		return nil, err
	}
	return roleNameList, nil
}

// GetList 获取权限列表
func (s *SysRoleService) GetList(searchParams *model.SysRoleGetListReq) ([]*model.SysRoles, error) {
	roleList := ([]*model.SysRoles)(nil)
	modelObj := dao.SysRoles.Safe()
	if searchParams.Name != "" {
		modelObj = modelObj.WhereLike(dao.SysRoles.Columns.Name, "%"+searchParams.Name+"%")
	}
	if searchParams.DisplayName != "" {
		modelObj = modelObj.WhereLike(dao.SysRoles.Columns.DisplayName, "%"+searchParams.DisplayName+"%")
	}
	if err := modelObj.Order(dao.SysRoles.Columns.OrderNum + " ASC," + dao.SysRoles.Columns.RoleId + " ASC").Scan(&roleList); err != nil {
		return nil, err
	}
	return roleList, nil
}

// BuildTree 构建树结构数据,(由于需要保留菜单结构数据，因此每一次树结构菜单都需要在对应的service中实现，使用公共的树方法无法还原原始菜单数据)
func (s *SysRoleService) BuildTree(resources []model.SysRoleTree) []*model.SysRoleTree {
	//定义根树，既id=0的根节点，我用的时候并不存在于数据库
	var rootResource = model.SysRoleTree{}
	//创建一个map，把父级相同的地址归纳起来
	DataMap := make(map[uint][]*model.SysRoleTree, len(resources))
	//寻找对应的父级，添加子节点集合
	for key := range resources {
		pid := resources[key].ParentId
		DataMap[pid] = append(DataMap[pid], &resources[key])
	}
	for key := range resources {
		if resources[key].ParentId == 0 {
			rootResource.Children = append(rootResource.Children, &resources[key])
		}
		resources[key].Children = DataMap[resources[key].RoleId]
	}
	// 添加完成，既建立树形关系完成
	return rootResource.Children
}

// SaveRole 保存角色
func (s *SysRoleService) SaveRole(data *model.SysRoleSaveReq) error {
	//使用事务闭包
	return dao.SysRoles.DB.Transaction(func(tx *gdb.TX) error {
		//保存角色数据
		_, err := dao.SysRoles.TX(tx).Data(data).Save()
		if err != nil {
			return err
		}
		//保存角色关联权限数据
		//先删除已有数据（硬删）
		_, err = dao.SysPermissionRoles.TX(tx).Unscoped().Where(dao.SysPermissionRoles.Columns.RoleId, data.RoleId).Delete()
		if err != nil {
			return nil
		}
		//批量添加关联数据
		var permRoleList []model.SysPermissionRoles
		for _, permId := range data.PermIdsArr {
			permRoleList = append(permRoleList, model.SysPermissionRoles{RoleId: data.RoleId, PermId: gconv.Uint(permId)})
		}
		_, err = dao.SysPermissionRoles.TX(tx).Save(permRoleList)
		if err != nil {
			return nil
		}
		return nil
	})
}

// DelRole 删除角色
func (s SysRoleService) DelRole(roleIds []uint) error {
	//使用事务必要
	return dao.SysRoles.DB.Transaction(func(tx *gdb.TX) error {
		//删除角色数据
		_, err := dao.SysRoles.TX(tx).WhereIn(dao.SysRoles.Columns.RoleId, roleIds).Delete()
		if err != nil {
			return err
		}
		//删除相关权限数据（硬删）
		_, err = dao.SysPermissionRoles.TX(tx).Unscoped().WhereIn(dao.SysPermissionRoles.Columns.RoleId, roleIds).Delete()
		if err != nil {
			return err
		}
		return nil
	})
}
